package utils

import (
	"math"
	"strconv"
)

// 只向外暴露了Mm
var Mm = new(myMath)

type myMath struct{}

func (c *myMath) MaxInt(a int, b int) int {
	if a > b {
		return a
	}
	return b
}

func (c *myMath) MaxFloat(a float64, b float64) float64 {
	if a > b {
		return a
	}
	return b
}

type AllInt interface {
	int | int8 | int16 | int32 | int64
}

// 多个只能这么写，一个才能像ts的type一样
type AllFloat interface {
	float32 | float64
}

// 使用泛型
func MaxAny[T AllInt | AllFloat](a, b T) T {
	if a > b {
		return a
	}

	return b
}

func MinAny[T AllInt | AllFloat](a, b T) T {
	if a < b {
		return a
	}
	return b
}

func Get[T any]() T {
	var t T
	var ti any = &t
	switch v := ti.(type) {
	case *int:
		*v = 18
	}

	return t
}

// 对float64四舍五入保留n位小数
func RoundFloat64(f float64, n int) float64 {
	return float64(RoundInt(f*math.Pow10(n))) / math.Pow10(n)
}

func RoundInt(f float64) float64 {
	return math.Trunc(f + 0.5)
}

func Float64ToFixedStr(f float64, n int) string {
	return strconv.FormatFloat(f, 'f', n, 64)
}

// 在切片的首个位置添加元素
func Prepend(slice []string, str string) []string {
	slice = append(slice, str)
	copy(slice[1:], slice)
	slice[0] = str
	return slice
}

// float64保留位小数
func Float64ToStr(f float64) string {
	return strconv.FormatFloat(f, 'f', -1, 64)
}

// float64保留位小数
func Float64Fixed(f float64, n int) float64 {
	//return math.Trunc(f*math.Pow10(n)) / math.Pow10(n)
	//	四舍五入
	return math.Round(f*math.Pow10(n)) / math.Pow10(n)
}

// 字符串转float64
func StrToFloat64(str string) float64 {
	f, _ := strconv.ParseFloat(str, 64)
	return f
}

// 计算[]float64的平均值
func AverageFloat64(arr []float64) float64 {
	var sum float64
	for _, v := range arr {
		sum += v
	}
	return sum / float64(len(arr))
}

// Tolerance
func Tolerance(a, b, tolerance float64) bool {
	//return math.Abs(a-b) < tolerance
	//	两个角度的差值，330和30，应该是40，而不是300
	diff := math.Abs(a - b)
	if diff > 180 {
		diff = 360 - diff
	}
	return diff < tolerance
}

// // float64保留位小数, 8.235 -> 8.0 8.6 -> 8.5
func FindClosestFraction(decimal float64, maxDenominator int) (int, int) {
	var closestNumerator, closestDenominator int
	var minDifference float64 = math.MaxFloat64

	for denominator := 1; float64(denominator) <= float64(maxDenominator); denominator++ {
		// Skip denominators that do not end in .0 or .5
		if denominator%2 != 0 && denominator%5 != 0 {
			continue
		}

		for numerator := 0; float64(numerator) <= float64(maxDenominator)*decimal; numerator++ {
			// Skip numerators that do not end in .0 or .5
			if numerator%2 != 0 && numerator%5 != 0 {
				continue
			}

			fraction := float64(numerator) / float64(denominator)
			difference := math.Abs(decimal - fraction)

			if difference < minDifference {
				closestNumerator = numerator
				closestDenominator = denominator
				minDifference = difference
			}
		}
	}

	// Simplify the fraction if possible
	gcd := gcd(closestNumerator, closestDenominator)
	closestNumerator /= gcd
	closestDenominator /= gcd

	return closestNumerator, closestDenominator
}

// gcd calculates the greatest common divisor of a and b.
func gcd(a, b int) int {
	for b != 0 {
		a, b = b, a%b
	}
	return a
}
